package com.yourenbang.lingyun.transaction.web.service.impl.pay.withdraw;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.response.AlipayDataBillBalanceQueryResponse;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.xxl.job.core.log.XxlJobLogger;
import com.yourenbang.lingyun.constants.AppId;
import com.yourenbang.lingyun.constants.BizCodeMessages;
import com.yourenbang.lingyun.constants.Constant;
import com.yourenbang.lingyun.constants.enums.LetterCodeEnum;
import com.yourenbang.lingyun.constants.enums.PlatNoEnums;
import com.yourenbang.lingyun.constants.enums.pay.PayFromEnum;
import com.yourenbang.lingyun.constants.enums.pay.PayTypeEnum;
import com.yourenbang.lingyun.constants.enums.table.FundAccountWithdrawPaymentBillEnum;
import com.yourenbang.lingyun.constants.enums.table.FundAccountWithdrawPaymentEnum;
import com.yourenbang.lingyun.core.exception.BizRuntimeException;
import com.yourenbang.lingyun.core.exception.SysBizException;
import com.yourenbang.lingyun.core.exception.UserBizException;
import com.yourenbang.lingyun.core.message.Result;
import com.yourenbang.lingyun.core.util.KLog;
import com.yourenbang.lingyun.core.util.date.DateFormat;
import com.yourenbang.lingyun.core.util.http.HttpClientUtil;
import com.yourenbang.lingyun.domain.FundAccountWithdrawPaymentBill;
import com.yourenbang.lingyun.domain.FundAccountWithdrawPaymentBillExample;
import com.yourenbang.lingyun.domain.PayType;
import com.yourenbang.lingyun.mapper.FundAccountMapper;
import com.yourenbang.lingyun.mapper.FundAccountWithdrawPaymentBillMapper;
import com.yourenbang.lingyun.mapper.PayChannelMapper;
import com.yourenbang.lingyun.openapi.api.service.client.ClientService;
import com.yourenbang.lingyun.transaction.config.AcmTransactionParams;
import com.yourenbang.lingyun.transaction.exception.WichdrawFailException;
import com.yourenbang.lingyun.transaction.exception.WichdrawWaitException;
import com.yourenbang.lingyun.transaction.mapper.TransactionFundAccountWithdrawPaymentBillMapper;
import com.yourenbang.lingyun.transaction.mapper.TransactionFundAccountWithdrawPaymentMapper;
import com.yourenbang.lingyun.transaction.mapper.TransactionPayTypeMapper;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.AliFundTransToaccountTransferDTO;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.FundPayApiDTO;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.fusuilinggong.FuSuiLingGongAgentPayDTO;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.fusuilinggong.FuSuiLingGongAgentPayQueryDTO;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.linghuisuan.LinghuisuanAgentpayDTO;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.linghuisuan.LinghuisuanAgentpayQueryDTO;
import com.yourenbang.lingyun.transaction.web.domain.dto.pay.yunhuisuan.YunhuisuanAgentpayDTO;
import com.yourenbang.lingyun.transaction.web.domain.po.FundAccountWithdrawPayment;
import com.yourenbang.lingyun.transaction.web.domain.po.T1AlarmAmountVO;
import com.yourenbang.lingyun.transaction.web.domain.vo.pay.FundPayApiVO;
import com.yourenbang.lingyun.transaction.web.domain.vo.pay.hjtx.AgentpayVO;
import com.yourenbang.lingyun.transaction.web.service.CommonService;
import com.yourenbang.lingyun.transaction.web.service.pay.withdraw.WithdrawFundService;
import com.yourenbang.lingyun.transaction.web.service.pay.withdraw.WithdrawPayService;
import com.yourenbang.lingyun.transaction.web.service.pay.withdraw.channel.AliWithdrawService;
import com.yourenbang.lingyun.transaction.web.service.pay.withdraw.channel.FuSuiLingGongService;
import com.yourenbang.lingyun.transaction.web.service.pay.withdraw.channel.YunHuiSuanService;
import com.yourenbang.mcenter.api.model.dto.letter.SendLetterDTO;
import com.yourenbang.mcenter.api.service.letter.McenterRpcLetterService;
import com.yourenbang.transaction.api.service.pay.PayTypeApiService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service("fundPayService")
public class WithdrawPayServiceImpl implements WithdrawPayService {

    @Autowired
    private TransactionPayTypeMapper transactionPayTypeMapper;
    @Autowired
    private TransactionFundAccountWithdrawPaymentBillMapper transactionFundAccountWithdrawPaymentBillMapper;
    @Autowired
    private McenterRpcLetterService mcenterRpcLetterService;
    @Autowired
    private PayChannelMapper payChannelMapper;
    @Autowired
    private CommonService commonService;
    @Autowired
    private AliWithdrawService aliWithdrawService;
    @Autowired
    private PayTypeApiService payTypeApiService;
    @Autowired
    ClientService clientService;
    @Autowired
    private YunHuiSuanService yunHuiSuanService;
    @Autowired
    private FundAccountMapper fundAccountMapper;
    @Autowired
    private FuSuiLingGongService fuSuiLingGongService;
    @Autowired
    private AcmTransactionParams acmTransactionParams;
    @Autowired
    private TransactionFundAccountWithdrawPaymentMapper fundAccountWithdrawPaymentMapper;
    @Autowired
    private FundAccountWithdrawPaymentBillMapper fundAccountWithdrawPaymentBillMapper;

    public static final Short STATUS_OFF = new Short("0");

    /**
     * 当前代付方式有效性检查
     *
     * @param withdrawPayType
     * @param platNo
     * @return
     */
    @Override
    public Result withDrawPreCheck(String withdrawPayType, Short platNo) {

        //如果是银行卡提现,检查是否有有效的代付渠道
        if (PayTypeEnum.BANK_CARD_PAY.isEquals(withdrawPayType)) {

            PayType payType = transactionPayTypeMapper.getBankCardPayTypeByPayFrom(PayFromEnum.yxy_withdraw_ally_all.getCode(), platNo);
            if (Objects.isNull(payType)) {
                throw new UserBizException(BizCodeMessages.WITHDRAW_PAY_TYPE_OFF);
            }

        }

        PayType payType = transactionPayTypeMapper.getPayType(withdrawPayType, PayFromEnum.yxy_withdraw_ally_all.getCode());

        if (Objects.isNull(payType)) {
            Result.builder().fail(BizCodeMessages.WITHDRAW_PAY_TYPE_OFF, "支付方式不可用");
        }

        if (Objects.isNull(payType.getPayChannel()) || payType.getStatus().equals(STATUS_OFF)) {
            Result.builder().fail(BizCodeMessages.WITHDRAW_PAY_TYPE_OFF, "支付通道不可用");
        }

        return Result.builder().success();

    }

    /**
     * 提现
     * <p>
     * 注意: 提现前,需调用 {@link #withDrawPreCheck(String, Short)} 进行有效性检查
     *
     * @throws WichdrawFailException 明确失败
     */
    @Override
    public FundPayApiVO withDraw(FundPayApiDTO dto) {

        KLog.warn("【提现】入参:{}", dto.toJSON());

        if (!commonService.isProd()) {

            BigDecimal a;
            if (PayTypeEnum.YUNHUISUAN.isEquals(dto.getPayType())) {
                //云汇算最低限额有差异
                a = new BigDecimal("10");
            } else {
                a = new BigDecimal("0.1");
            }
            KLog.info("【提现】非生产环境,提现固定 {} 元,入参:{}",a,dto.toJSON());

            dto.setAmt(a);
        }

        PayType payType = transactionPayTypeMapper.getPayType(dto.getPayType(), dto.getPayFrom());
        if (Objects.isNull(payType)) {
            throw new UserBizException(BizCodeMessages.WITHDRAW_PAY_TYPE_OFF);
        }
        if (Objects.isNull(payType.getPayChannel()) || payType.getStatus().equals(STATUS_OFF)) {
            throw new UserBizException(BizCodeMessages.WITHDRAW_PAY_TYPE_OFF);
        }

        FundPayApiVO fundPayApiVO = new FundPayApiVO();
        fundPayApiVO.setPayChannelId(payType.getPayChannel());

        if (PayTypeEnum.ALIPAY.isEquals(dto.getPayType())) {
            //支付宝提现
            AliFundTransToaccountTransferDTO transferDTO = new AliFundTransToaccountTransferDTO();
            transferDTO.setPlatNo(dto.getPlatNo());
            transferDTO.setPayChannelId(payType.getPayChannel());
            transferDTO.setPayFrom(dto.getPayFrom());
            transferDTO.setOrderNO(dto.getOrderNo());
            transferDTO.setAliAccount(dto.getAccountNo());
            transferDTO.setRealName(dto.getName());
            transferDTO.setAmount(dto.getAmt());
            Map<String, String> typeParam = payTypeApiService.getPayParamsByChannel(payType.getPayChannel());
            if (StringUtils.isBlank(typeParam.get("appCertPath"))) {
                AlipayFundTransToaccountTransferResponse aliResponse = aliWithdrawService.aliFundTransToaccountTransfer(transferDTO);
                fundPayApiVO.setThirdOrderId(aliResponse.getOrderId());
                fundPayApiVO.setThirdPayStatus(aliResponse.getSubCode());
                fundPayApiVO.setThirdPayStatusDesc(aliResponse.getSubMsg());
                fundPayApiVO.setContext(JSON.toJSONString(aliResponse));
            } else {
                //新提现接口
                AlipayFundTransUniTransferResponse aliResponse = aliWithdrawService.alipayFundTransUniTransfer(transferDTO);
                fundPayApiVO.setThirdOrderId(aliResponse.getPayFundOrderId());
                fundPayApiVO.setThirdPayStatus(aliResponse.getSubCode());
                fundPayApiVO.setThirdPayStatusDesc(aliResponse.getSubMsg());
                fundPayApiVO.setContext(JSON.toJSONString(aliResponse));
            }
        } else if (PayTypeEnum.LINGHUISUAN.isEquals(dto.getPayType())) {
            //灵会算代付签约检查,未签约先完成签约
//            Result<String> result = lingHuiSuanService.alreadySign(PayFromEnum.getPayFrom(dto.getPayFrom()), dto.getUserBaseId());
//            if (result.isSuccess() && ObjectUtils.isNotEmpty(result.getData())) {
//                String msg = String.format("提现签约异常,请确认是否完成代付签约,[%d]%s",
//                        BizCodeMessages.WITHDRAW_SIGN_OFF.getValue(),
//                        BizCodeMessages.WITHDRAW_SIGN_OFF.getDesc()
//                );
//                throw new WichdrawFailException(msg);
//            } else if (result.isFail()) {
//                throw new WichdrawFailException(BizCodeMessages.TRANSACTION_USER_SIGN_ERROR.getDesc());
//            }
//
//            // 发起代付
//            LinghuisuanAgentpayDTO linghuisuanAgentpayDTO = new LinghuisuanAgentpayDTO();
//            linghuisuanAgentpayDTO.setPayChannelId(payType.getPayChannel());
//            linghuisuanAgentpayDTO.setOrderNo(dto.getOrderNo());
//            linghuisuanAgentpayDTO.setAmt(dto.getAmt());
//            linghuisuanAgentpayDTO.setAccountName(dto.getName());
//            linghuisuanAgentpayDTO.setPhone(dto.getPhone());
//            linghuisuanAgentpayDTO.setAccountNo(dto.getAccountNo());
//            linghuisuanAgentpayDTO.setIdCard(dto.getIdCard());
//
//            AgentpayVO agentpayVO = lingHuiSuanService.agentpay(linghuisuanAgentpayDTO);
//
//            fundPayApiVO.setThirdOrderId(agentpayVO.getSerialNumber());
//            fundPayApiVO.setThirdPayStatus(agentpayVO.getCode());
//            fundPayApiVO.setThirdPayStatusDesc(agentpayVO.getMessage());
//            fundPayApiVO.setContext(agentpayVO.toJSON());

        } else if (PayTypeEnum.YUNHUISUAN.isEquals(dto.getPayType())) {

            //云会算代付签约检查,未签约先完成签约
//            Result<String> result = yunHuiSuanService.alreadySign(PayFromEnum.getPayFrom(dto.getPayFrom()), dto.getUserBaseId());
//            if (result.isSuccess() && ObjectUtils.isNotEmpty(result.getData())) {
//                String msg = String.format("提现签约异常,请确认是否完成代付签约,[%d]%s",
//                        BizCodeMessages.WITHDRAW_SIGN_OFF.getValue(),
//                        BizCodeMessages.WITHDRAW_SIGN_OFF.getDesc()
//                );
//                throw new WichdrawFailException(msg);
//            } else if (result.isFail()) {
//                throw new WichdrawFailException(BizCodeMessages.TRANSACTION_USER_SIGN_ERROR.getDesc());
//            }

            // 发起代付

            // 将元转为分
            BigDecimal amountFen = dto.getAmt().multiply(BigDecimal.valueOf(100));

            YunhuisuanAgentpayDTO yunhuisuanAgentpayDTO = new YunhuisuanAgentpayDTO();
            yunhuisuanAgentpayDTO.setPayChannelId(payType.getPayChannel());
            yunhuisuanAgentpayDTO.setOrderNo(dto.getOrderNo());
            yunhuisuanAgentpayDTO.setAmt(amountFen);
            yunhuisuanAgentpayDTO.setAccountName(dto.getName());
            yunhuisuanAgentpayDTO.setPhone(dto.getPhone());
            yunhuisuanAgentpayDTO.setAccountNo(dto.getAccountNo());
            yunhuisuanAgentpayDTO.setIdCard(dto.getIdCard());

            AgentpayVO agentpayVO = yunHuiSuanService.agentpay(yunhuisuanAgentpayDTO);

            fundPayApiVO.setThirdOrderId(agentpayVO.getSerialNumber());
            fundPayApiVO.setThirdPayStatus(agentpayVO.getCode());
            fundPayApiVO.setThirdPayStatusDesc(agentpayVO.getMessage());
            fundPayApiVO.setContext(agentpayVO.toJSON());

        } else if (PayTypeEnum.FUSUILINGGONG.isEquals(dto.getPayType())) {
            //代付签约检查,未签约先完成签约
            boolean result = fuSuiLingGongService.alreadySign(dto.getUserBaseId());
            if (!result) {
                throw new WichdrawFailException(BizCodeMessages.TRANSACTION_USER_SIGN_ERROR.getDesc());
            }

            // 发起代付
            FuSuiLingGongAgentPayDTO agentPayDTO = new FuSuiLingGongAgentPayDTO();
            agentPayDTO.setPayChannelId(payType.getPayChannel());
            agentPayDTO.setOrderNo(dto.getOrderNo());
            agentPayDTO.setAmt(dto.getAmt());
            agentPayDTO.setAccountName(dto.getName());
            agentPayDTO.setPhone(dto.getPhone());
            agentPayDTO.setAccountNo(dto.getAccountNo());
            agentPayDTO.setIdCard(dto.getIdCard());

            AgentpayVO agentpayVO = fuSuiLingGongService.agentPay(agentPayDTO);

            fundPayApiVO.setThirdOrderId(agentpayVO.getSerialNumber());
            fundPayApiVO.setThirdPayStatus(agentpayVO.getCode());
            fundPayApiVO.setThirdPayStatusDesc(agentpayVO.getMessage());
            fundPayApiVO.setContext(agentpayVO.toJSON());

        } else {

            KLog.warn("【提现】不支持的提现方式,入参:{}", dto.toJSON());
            throw new BizRuntimeException(BizCodeMessages.WITHDRAW_PAY_TYPE_OFF);

        }

        return fundPayApiVO;
    }

    /**
     * 提现查询,如果失败,会抛异常
     * 应明确返回是否成功,增加可读性
     *
     * @throws WichdrawFailException 明确失败
     */
    @Override
    public void withDrawQuery(FundAccountWithdrawPayment fund) {

        JSONObject respDataOjb = JSON.parseObject(fund.getThirdRequestDesc());
        if (respDataOjb == null) {
            respDataOjb = new JSONObject();
        }

        if (Objects.isNull(fund.getPayChannelId())) {
            PayType payType = transactionPayTypeMapper.getPayType(fund.getPayGetway(), fund.getWithdrawType());
            if (Objects.isNull(payType)) {
                throw new UserBizException(BizCodeMessages.UNKNOWN_ERROR, "支付方式不可用");
            }
            if (Objects.isNull(payType.getPayChannel())) {
                throw new UserBizException(BizCodeMessages.UNKNOWN_ERROR, "支付通道不可用");
            }
            fund.setPayChannelId(payType.getPayChannel());
        }

        //TODO 重构优化注意 一般的,不应使用异常替代返回值,返回更直观
        if (PayTypeEnum.LINGHUISUAN.isEquals(fund.getPayGetway())) {
            //灵会算
//            LinghuisuanAgentpayQueryDTO dto = new LinghuisuanAgentpayQueryDTO();
//            dto.setPayChannelId(fund.getPayChannelId());
//            dto.setOrderNo(fund.getOrderSn());
//            dto.setOutOrderNo(fund.getThirdOrderId());
//            boolean isOk = lingHuiSuanService.checkAgentpayResult(dto);
//            if (!isOk) {
//                throw new WichdrawWaitException("代付处理中");
//            }
        } else if (PayTypeEnum.FUSUILINGGONG.isEquals(fund.getPayGetway())) {
            //灵会算
            FuSuiLingGongAgentPayQueryDTO dto = new FuSuiLingGongAgentPayQueryDTO();
            dto.setOrderNo(fund.getOrderSn());
            dto.setOutOrderNo(fund.getThirdOrderId());
            boolean isOk = fuSuiLingGongService.checkAgentPayResult(dto);
            if (!isOk) {
                throw new WichdrawWaitException("代付处理中");
            }
        }else {
            KLog.info("【提现查询任务】不支持的提现方式,订单:{}", fund);
            throw new BizRuntimeException(BizCodeMessages.UNKNOWN_ERROR, "不支持的提现方式");
        }
    }

    /**
     * 回调（post请求,参数放body）
     *
     * @throws WichdrawFailException 明确失败
     */
    @Override
    public Result<FundAccountWithdrawPayment> withDrawNoticeBody(String payType, String param) {

        if (PayTypeEnum.LINGHUISUAN.isEquals(payType)) {
            return null;
            //return lingHuiSuanService.withdrawNotice(param);

        } else if (PayTypeEnum.YUNHUISUAN.isEquals(payType)) {

            return yunHuiSuanService.withdrawNotice(param);

        }else if (PayTypeEnum.FUSUILINGGONG.isEquals(payType)) {

            return fuSuiLingGongService.withdrawNotice(param);

        } else {

            KLog.warn("【提现回调body】不支持的提现支付方式:{}", payType);
            throw new BizRuntimeException(BizCodeMessages.PARAMS_ERROR, "回调代付类型未知");

        }

    }

    /**
     * 回调（post请求,参数放表单）
     *
     * @throws WichdrawFailException 明确失败
     */
    @Override
    public FundAccountWithdrawPayment withDrawNoticeParam(String payType, Map<String, String> param) {
        //注意: 目前未用到,重新启用需调试确认
//        if (PayTypeEnum.LINGHUISUAN.isEquals(payType)) {
//        }
        KLog.info("【提现回调param】不支持的提现支付方式:{}", payType);
        throw new BizRuntimeException(BizCodeMessages.UNKNOWN_ERROR, "不支持的提现方式");

    }

    @Override
    public void withdrawSigne(String param) {
        //lingHuiSuanService.signNotice(param);
    }

    @Override
    public Result withDrawT1Pay(String batchNumber) {
        throw new SysBizException(BizCodeMessages.UNKNOWN_ERROR, "不支持T1操作");
//        List<Short> platNos = new ArrayList<>();
//        platNos.add(PlatNoEnums.KLKS.getCode());
//        platNos.add(PlatNoEnums.YXY.getCode());
//        Result result = validCheck(platNos, batchNumber);
//        if (!result.isSuccess()) {
//            return result;
//        }
//        new Thread(() -> {
//            for (Short platNo : platNos) {
//                List<FundAccountWithdrawPayment> fundAccountWithdrawPayments = fundAccountWithdrawPaymentMapper.queryT1WithdrawWaitPay(platNo, batchNumber);
//                //是否已更新渠道
//                boolean alipayFlag = false;
//                boolean bankCardFlag = false;
//                Map<String, PayType> payTypeMap = new HashMap<>();
//                for (FundAccountWithdrawPayment fundAccountWithdrawPayment : fundAccountWithdrawPayments) {
//                    fundAccountWithdrawPayment.setPlatNo(platNo);
//                    //t1且非贝管家才请求提现方法
//                    if (FundAccountWithdrawPaymentEnum.SettleTypeEnum.T1.isEquals(fundAccountWithdrawPayment.getSettleType())) {
////                            && !StringUtils.equalsAny(fundAccountWithdrawPayment.getPayGetway(), PayTypeEnum.BEIGUANJIA_COMPANY.getCode(), PayTypeEnum.BEIGUANJIA.getCode())) {
//                        FundAccountWithdrawPayment upWithPay = new FundAccountWithdrawPayment(platNo);
//                        FundPayApiDTO apiDTO = generateFundPayApiDTO(fundAccountWithdrawPayment, payTypeMap, batchNumber, bankCardFlag);
//                        if (!PlatNoEnums.KLKS.isEquals(platNo)) {
//                            upWithPay.setThirdRequestDesc(apiDTO.toJSON());
//                        }
//                        upWithPay.setFundAccountWithdrawPaymentId(fundAccountWithdrawPayment.getFundAccountWithdrawPaymentId());
//                        upWithPay.setRequestDate(LocalDateTime.now());
//                        //请求提现
//                        try {
//                            FundPayApiVO fundPayApiVO = this.withDraw(apiDTO);
//                            if (PayTypeEnum.ALIPAY.isEquals(fundAccountWithdrawPayment.getPayGetway()) && !alipayFlag) {
//                                FundAccountWithdrawPaymentBill fundAccountWithdrawPaymentBillPayChannel = new FundAccountWithdrawPaymentBill();
//                                fundAccountWithdrawPaymentBillPayChannel.setPayChannelId(fundPayApiVO.getPayChannelId());
//                                fundAccountWithdrawPaymentBillPayChannel.setPayChannelName(payChannelMapper.selectByPrimaryKey(fundPayApiVO.getPayChannelId()).getName());
//                                FundAccountWithdrawPaymentBillExample fundAccountWithdrawPaymentBillExamplePayChannel = new FundAccountWithdrawPaymentBillExample();
//                                fundAccountWithdrawPaymentBillExamplePayChannel.createCriteria().andBatchNumberEqualTo(batchNumber)
//                                        .andPlatNoEqualTo(platNo).andPayChannelTypeEqualTo(FundAccountWithdrawPaymentBillEnum.PayChannelTypeEnum.ALIPAY.getCode());
//                                fundAccountWithdrawPaymentBillMapper.updateByExampleSelective(fundAccountWithdrawPaymentBillPayChannel, fundAccountWithdrawPaymentBillExamplePayChannel);
//                                alipayFlag = true;
//                            }
//                            upWithPay.setPayChannelId(fundPayApiVO.getPayChannelId());
//                            upWithPay.setThirdOrderId(fundPayApiVO.getThirdOrderId());
//                            upWithPay.setThirdPayStatus(fundPayApiVO.getThirdPayStatus());
//                            upWithPay.setThirdPayStatusDesc(fundPayApiVO.getThirdPayStatusDesc());
//                            upWithPay.setContext(fundPayApiVO.getContext());
//                            upWithPay.setThirdRequestStatus(FundAccountWithdrawPayment.THIRDREQUESTSTATUS_SUCC);
//                            upWithPay.setSuccessDate(LocalDateTime.now());
//                            upWithPay.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_WAIT.getCode());
//                            Integer upPay = fundAccountWithdrawPaymentMapper.updateById(upWithPay);
//                            BizAssertUtils.assertOne(upPay, "修改提现状态失败");
//                        } catch (BizRuntimeException e) {
//                            KLog.info("【凌云日结提现】提现失败, 业务失败,{},入参:{}", e.getMessage(), fundAccountWithdrawPayment.toJSON());
//                            upWithPay.setThirdRequestStatus(FundAccountWithdrawPayment.THIRDREQUESTSTATUS_SUCC);
//                            upWithPay.setErrors(e.getMessage());
//                            upWithPay.setSuccessDate(LocalDateTime.now());
//                            upWithPay.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_FAIL.getCode());
//                            Integer upPay = fundAccountWithdrawPaymentMapper.updateById(upWithPay);
//                            fundAccountWithdrawPayment.setErrors(e.getMessage());
//                            withdrawFailLetter(fundAccountWithdrawPayment);
//                            //记录失败笔数金额
//                            recordFailAmount(fundAccountWithdrawPayment);
//                            continue;
//                        } catch (WichdrawFailException e) {
//
//                            KLog.info("【凌云日结提现】提现失败, 通道返回失败,{},入参:{}", e.getMessage(), fundAccountWithdrawPayment.toJSON());
//                            upWithPay.setThirdRequestStatus(FundAccountWithdrawPayment.THIRDREQUESTSTATUS_SUCC);
//                            upWithPay.setErrors(e.getMessage());
//                            upWithPay.setSuccessDate(LocalDateTime.now());
//                            upWithPay.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_FAIL.getCode());
//                            Integer upPay = fundAccountWithdrawPaymentMapper.updateById(upWithPay);
//                            withdrawFundService.returnFund(fundAccountWithdrawPayment.getFundAccountWithdrawPaymentId(), fundAccountWithdrawPayment.getPlatNo());
//                            fundAccountWithdrawPayment.setErrors(e.getMessage());
//                            withdrawFailLetter(fundAccountWithdrawPayment);
//                            //记录失败笔数金额
//                            recordFailAmount(fundAccountWithdrawPayment);
//                            continue;
//
//                        } catch (Exception e) {
//                            KLog.error("【凌云日结提现】异常,{},入参:{}", e.getMessage(), fundAccountWithdrawPayment.toJSON(), e);
//                            upWithPay.setThirdRequestStatus(FundAccountWithdrawPayment.THIRDREQUESTSTATUS_ERROR);
//                            upWithPay.setErrors(e.getMessage());
//                            upWithPay.setSuccessDate(LocalDateTime.now());
//                            upWithPay.setWithdrawStatus(WithDrawStatusEnum.WITHDRAW_STATUS_FAIL.getCode());
//                            fundAccountWithdrawPaymentMapper.updateById(upWithPay);
//                            fundAccountWithdrawPayment.setErrors(e.getMessage());
//                            withdrawFailLetter(fundAccountWithdrawPayment);
//                            //记录失败笔数金额
//                            recordFailAmount(fundAccountWithdrawPayment);
//                            continue;
//                        }
//                    }
//                    payInterval();
//                }
//            }
//            //更新为已完成
//            FundAccountWithdrawPaymentBillExample fundAccountWithdrawPaymentBillExampleEnd = new FundAccountWithdrawPaymentBillExample();
//            fundAccountWithdrawPaymentBillExampleEnd.createCriteria().andBatchNumberEqualTo(batchNumber)
//                    .andIsDelEqualTo(Constant.NORMAL).andPayStatusEqualTo(FundAccountWithdrawPaymentBillEnum.PayStatusEnum.PAYING.getCode());
//            FundAccountWithdrawPaymentBill fundAccountWithdrawPaymentBillUpEnd = new FundAccountWithdrawPaymentBill();
//            fundAccountWithdrawPaymentBillUpEnd.setPayStatus(FundAccountWithdrawPaymentBillEnum.PayStatusEnum.PAY_SUCCESS.getCode());
//            fundAccountWithdrawPaymentBillUpEnd.setPayTimeEnd(LocalDateTime.now());
//            //更新为已完成
//            fundAccountWithdrawPaymentBillMapper.updateByExampleSelective(fundAccountWithdrawPaymentBillUpEnd, fundAccountWithdrawPaymentBillExampleEnd);
//        }).start();
//        return Result.builder().success();
    }

    private void recordFailAmount(FundAccountWithdrawPayment fundAccountWithdrawPayment) {
        //更新失败金额笔数
        if (StringUtils.isNotBlank(fundAccountWithdrawPayment.getBatchNumber()) && FundAccountWithdrawPaymentEnum.SettleTypeEnum.T1.isEquals(fundAccountWithdrawPayment.getSettleType())) {
            Short payChannelType = PayTypeEnum.ALIPAY.isEquals(fundAccountWithdrawPayment.getPayGetway()) ? FundAccountWithdrawPaymentBillEnum.PayChannelTypeEnum.ALIPAY.getCode()
                    : FundAccountWithdrawPaymentBillEnum.PayChannelTypeEnum.BANK_CARD.getCode();
            transactionFundAccountWithdrawPaymentBillMapper.updateFailCount(fundAccountWithdrawPayment.getBatchNumber(),
                    payChannelType, fundAccountWithdrawPayment.getPlatNo(), fundAccountWithdrawPayment.getInAmount());
        }
    }

    /**
     * 发放间隔
     */
    private void payInterval() {
        //每次循环是否需要睡眠 .acm配置睡眠时间 为0不睡.
        if (acmTransactionParams.getWithdrawalSettlePayTime() != 0) {
            try {
                TimeUnit.MILLISECONDS.sleep(acmTransactionParams.getWithdrawalSettlePayTime());
            } catch (Exception e) {
                log.error("日结发放睡眠异常", e);
            }
        }
    }

    /**
     * 发私信
     */
    private void withdrawFailLetter(FundAccountWithdrawPayment fund) {
        //发送提现失败私信
        //发送私信
        SendLetterDTO sendLetterDTO = new SendLetterDTO();
        sendLetterDTO.setPlatNo(fund.getPlatNo());
        sendLetterDTO.setUserBaseId(fundAccountMapper.selectByPrimaryKey(fund.getFundAccountId()).getUserBaseId());
        if (fund.getWithdrawType().equals(PayFromEnum.yxy_withdraw_mer.getCode())) {
            sendLetterDTO.setAppId(AppId.YXY_MER);
//        } else if (fund.getWithdrawType().equals(PayFromEnum.withdraw_mer.getCode())) {
//            sendLetterDTO.setAppId(AppId.KLKS_PRO);
        } else {
            if (PlatNoEnums.YXY.isEquals(fund.getPlatNo())) {
                sendLetterDTO.setAppId(AppId.YXY);
            } else {
                sendLetterDTO.setAppId(AppId.KLLC);
            }
        }
        Map<String, String> map = new HashMap<>();
        map.put("year", DateFormat.YEAR.format(fund.getCreateTime()));
        map.put("month", DateFormat.MONTH.format(fund.getCreateTime()));
        map.put("date", DateFormat.DAY.format(fund.getCreateTime()));

        map.put("amount", String.valueOf(fund.getAmount()));
        map.put("reason", String.valueOf(fund.getErrors()));
        sendLetterDTO.setMap(map);
        sendLetterDTO.setLetterCodeEnum(LetterCodeEnum.YXY_NOTICE_WITHDRAW_FAIL);
        mcenterRpcLetterService.send(sendLetterDTO);
    }

    /**
     * 检查各个渠道余额是否充足
     *
     * @return
     */
    private String checkBalanceAmount(String batchNumber) {
        List<T1AlarmAmountVO> t1AlarmAmountVOS = transactionPayTypeMapper.queryT1PayAmount(batchNumber);
        for (T1AlarmAmountVO t1AlarmAmountVO : t1AlarmAmountVOS) {
            BigDecimal balanceAmount = BigDecimal.ZERO;
            if (t1AlarmAmountVO.getName().contains("支付宝")) {
                AlipayDataBillBalanceQueryResponse balanceQueryResponse =
                        aliWithdrawService.alipayDataBillBalanceQuery(t1AlarmAmountVO.getPayChannelId());

                if (Objects.isNull(balanceQueryResponse)) {
                    log.info("查询支付宝商家账户当前余额查询返回空，payChannelId={}", t1AlarmAmountVO.getPayChannelId());
                    return t1AlarmAmountVO.getName() + ":查询余额失败,稍后再试";
                }

                balanceAmount = new BigDecimal(balanceQueryResponse.getAvailableAmount());
                if (t1AlarmAmountVO.getAmount().compareTo(balanceAmount) > 0) {
                    KLog.info("{}余额不足,channelId:{}", t1AlarmAmountVO.getName(), t1AlarmAmountVO.getPayChannelId());
                    return t1AlarmAmountVO.getName() + "余额:" + balanceAmount;
                }
            }

        }
        return null;
    }


    /**
     * 发起请求
     */
    private JSONObject initiateRequest(String url, String requestParam, String urlName) {

        String response = "";
        JSONObject jsonObject = null;
        int i = 1;
        while (i < 4) {

            try {
                i++;
                XxlJobLogger.log("【泰税康" + urlName + "】准备请求接口,url:{}, 请求参数:{}", url, requestParam);
                //请求接口
                if (StringUtils.isNotBlank(requestParam)) {
                    response = HttpClientUtil.httpPostRequest(url, requestParam);
                } else {
                    response = HttpClientUtil.httpPostRequest(url);
                }

                XxlJobLogger.log("【泰税康" + urlName + "】接口响应:{},入参:{}", response, requestParam);
                if (StringUtils.isNotBlank(response)) {
                    jsonObject = JSON.parseObject(response);
                    if (jsonObject.getInteger("code") == 200) {
                        return jsonObject;
                    }
                }
            } catch (Exception e) {
                if (i == 4) {
                    XxlJobLogger.log("【泰税康" + urlName + "】请求异常:{},入参:{}", e.getMessage(), requestParam);
                    throw new UserBizException(BizCodeMessages.TAISHUIKANG_RESPONSE_FAIL, e.getMessage());
                }
            }

            if (i == 4) {
                if (StringUtils.isBlank(response)) {
                    XxlJobLogger.log("【泰税康" + urlName + "】接口返回空,入参:{}", requestParam);
                    throw new UserBizException(BizCodeMessages.TAISHUIKANG_RESPONSE_NULL, "接口返回空");
                } else {
                    XxlJobLogger.log("【泰税康" + urlName + "】接口响应未成功,入参:{}", requestParam);
                    throw new UserBizException(BizCodeMessages.TAISHUIKANG_RESPONSE_UNSUCCESSFUL,
                            jsonObject.getString("message"));
                }
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
        return jsonObject;
    }

    /**
     * 检查通道是否可用
     *
     * @param platNos
     * @param batchNumber
     * @return
     */
    private Result checkPayType(List<Short> platNos, String batchNumber) {
        for (Short platNo : platNos) {
            //检查通道可用
            List<FundAccountWithdrawPayment> fundAccountWithdrawPayments = fundAccountWithdrawPaymentMapper.queryT1WithdrawWaitPayType(platNo, batchNumber);
            for (FundAccountWithdrawPayment fundAccountWithdrawPayment : fundAccountWithdrawPayments) {
                if (PayTypeEnum.BANK_CARD_PAY.isEquals(fundAccountWithdrawPayment.getPayGetway()) ||
                        PayTypeEnum.isBankCardEnum(fundAccountWithdrawPayment.getPayGetway())) {
                    PayType bankCardPayTypeByPayFrom = transactionPayTypeMapper.getBankCardPayTypeByPayFrom(fundAccountWithdrawPayment.getWithdrawType(), platNo);
                    if (Objects.isNull(bankCardPayTypeByPayFrom)) {
                        KLog.error("支付通道不可用:{}", fundAccountWithdrawPayment.toJSON());
                        return Result.builder().fail(BizCodeMessages.VALIDATOR_ERR, "支付通道不可用");
                    }
                } else {
                    PayType payType = transactionPayTypeMapper.getPayType(fundAccountWithdrawPayment.getPayGetway(), fundAccountWithdrawPayment.getWithdrawType());
                    if (payType == null) {
                        return Result.builder().fail(BizCodeMessages.VALIDATOR_ERR, "支付方式不可用");
                    }
                    if (payType.getPayChannel() == null) {
                        return Result.builder().fail(BizCodeMessages.VALIDATOR_ERR, "支付通道不可用");
                    }
                }
            }
        }
        return Result.builder().success();
    }

    /**
     * 有效性校验, 无问题后更新为处理中
     *
     * @param platNos
     * @param batchNumber
     * @return
     */
    private Result validCheck(List<Short> platNos, String batchNumber) {
        if (commonService.repeatSubmit("withDrawT1Pay:" + batchNumber, 120)) {
            return Result.builder().fail(BizCodeMessages.VALIDATOR_REPEAT_SUBMIT);
        }
        FundAccountWithdrawPaymentBillExample fundAccountWithdrawPaymentBillExample = new FundAccountWithdrawPaymentBillExample();
        fundAccountWithdrawPaymentBillExample.createCriteria().andBatchNumberEqualTo(batchNumber)
                .andIsDelEqualTo(Constant.NORMAL).andPayStatusEqualTo(FundAccountWithdrawPaymentBillEnum.PayStatusEnum.WAIT_PAY.getCode());
        List<FundAccountWithdrawPaymentBill> fundAccountWithdrawPaymentBills = fundAccountWithdrawPaymentBillMapper.selectByExample(fundAccountWithdrawPaymentBillExample);
        if (CollectionUtils.isEmpty(fundAccountWithdrawPaymentBills)) {
            return Result.builder().fail(BizCodeMessages.VALIDATOR_EMPTY_ERR, "不存在待发放账单");
        }
        Result result = checkPayType(platNos, batchNumber);
        if (!result.isSuccess()) {
            return result;
        }
        String s = checkBalanceAmount(batchNumber);
        if (StringUtils.isNotBlank(s)) {
            return Result.builder().fail(BizCodeMessages.TRANSACTION_AMOUNT_DEFICIENCY, s);
        }
        FundAccountWithdrawPaymentBill fundAccountWithdrawPaymentBillUp = new FundAccountWithdrawPaymentBill();
        fundAccountWithdrawPaymentBillUp.setPayStatus(FundAccountWithdrawPaymentBillEnum.PayStatusEnum.PAYING.getCode());
        fundAccountWithdrawPaymentBillUp.setPayTimeBegin(LocalDateTime.now());
        //先更新为处理中,开始发放时间
        fundAccountWithdrawPaymentBillMapper.updateByExampleSelective(fundAccountWithdrawPaymentBillUp, fundAccountWithdrawPaymentBillExample);
        return Result.builder().success();
    }

    private FundPayApiDTO generateFundPayApiDTO(FundAccountWithdrawPayment fundAccountWithdrawPayment, Map<String, PayType> payTypeMap, String batchNumber, boolean bankCardFlag) {
        FundPayApiDTO apiDTO = new FundPayApiDTO();

        apiDTO.setPlatNo(fundAccountWithdrawPayment.getPlatNo());
        apiDTO.setUserBaseId(fundAccountMapper.selectByPrimaryKey(fundAccountWithdrawPayment.getFundAccountId()).getUserBaseId());
        apiDTO.setPayFrom(fundAccountWithdrawPayment.getWithdrawType());
        if (PayTypeEnum.BANK_CARD_PAY.isEquals(fundAccountWithdrawPayment.getPayGetway()) || PayTypeEnum.isBankCardEnum(fundAccountWithdrawPayment.getPayGetway())) {
            if (Objects.isNull(payTypeMap.get(fundAccountWithdrawPayment.getWithdrawType()))) {
                PayType bankCardPayTypeByPayFrom = transactionPayTypeMapper.getBankCardPayTypeByPayFrom(fundAccountWithdrawPayment.getWithdrawType(), fundAccountWithdrawPayment.getPlatNo());
                payTypeMap.put(fundAccountWithdrawPayment.getWithdrawType(), bankCardPayTypeByPayFrom);
            }
            PayType payType = payTypeMap.get(fundAccountWithdrawPayment.getWithdrawType());

            if (!bankCardFlag) {
                FundAccountWithdrawPaymentBill fundAccountWithdrawPaymentBillPayChannel = new FundAccountWithdrawPaymentBill();
                fundAccountWithdrawPaymentBillPayChannel.setPayChannelId(payType.getPayChannel());
                fundAccountWithdrawPaymentBillPayChannel.setPayChannelName(payChannelMapper.selectByPrimaryKey(payType.getPayChannel()).getName());
                FundAccountWithdrawPaymentBillExample fundAccountWithdrawPaymentBillExamplePayChannel = new FundAccountWithdrawPaymentBillExample();
                fundAccountWithdrawPaymentBillExamplePayChannel.createCriteria().andBatchNumberEqualTo(batchNumber)
                        .andPlatNoEqualTo(fundAccountWithdrawPayment.getPlatNo()).andPayChannelTypeEqualTo(FundAccountWithdrawPaymentBillEnum.PayChannelTypeEnum.BANK_CARD.getCode());
                fundAccountWithdrawPaymentBillMapper.updateByExampleSelective(fundAccountWithdrawPaymentBillPayChannel, fundAccountWithdrawPaymentBillExamplePayChannel);
                bankCardFlag = true;
            }
            apiDTO.setPayType(fundAccountWithdrawPayment.getPayGetway());

        } else {
            apiDTO.setPayType(fundAccountWithdrawPayment.getPayGetway());
        }
        apiDTO.setOrderNo(fundAccountWithdrawPayment.getOrderSn());
        apiDTO.setAccountNo(fundAccountWithdrawPayment.getThirdAccount());
        apiDTO.setName(fundAccountWithdrawPayment.getUserName());
        apiDTO.setIdCard(fundAccountWithdrawPayment.getIdNumber());
        apiDTO.setPhone(fundAccountWithdrawPayment.getPhone());
        apiDTO.setAmt(fundAccountWithdrawPayment.getInAmount());
        apiDTO.setFee(fundAccountWithdrawPayment.getFee());
        return apiDTO;
    }
}

